package com.comtop.topcloud.device.service.scheduler;

import com.comtop.topcloud.device.enums.TimeGranularity;
import com.comtop.topcloud.device.model.mysql.DeviceBaseInfo;
import com.comtop.topcloud.device.model.mysql.EnergyEquipmentMonitorRefTag;
import com.comtop.topcloud.device.model.mysql.StatisticsTable;
import com.comtop.topcloud.device.service.DeviceBaseInfoService;
import com.comtop.topcloud.device.service.EnergyEquipmentMonitorRefTagService;
import com.comtop.topcloud.device.service.StatisticsTableService;
import com.comtop.topcloud.device.util.TimeUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RMapCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import plus.ojbk.influxdb.core.InfluxdbTemplate;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
@AllArgsConstructor
public class SchedulerService {

    private static final Logger logger = LoggerFactory.getLogger(SchedulerService.class);
    private final InfluxdbTemplate influxdbTemplate;
    private final DeviceBaseInfoService deviceBaseInfoService;

    public static final ThreadPoolExecutor EXE = new ThreadPoolExecutor(4, 8, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100000));

    private final StatisticsTableService statisticsTableService;

    private final EnergyEquipmentMonitorRefTagService energyEquipmentMonitorRefTagService;

    @Scheduled(cron = "5 0 * * * ?")// 每小时整点执行
    public void hourlyStatisticsTask() {
        RMapCache<String, EnergyEquipmentMonitorRefTag> refRMapCache = energyEquipmentMonitorRefTagService.getMonitorMaps();
        refRMapCache.keySet().forEach(key -> {
            EXE.execute(() -> {
                EnergyEquipmentMonitorRefTag energyEquipmentMonitorRefTag = refRMapCache.get(key);
                doStatisticsTask(TimeGranularity.HOUR, energyEquipmentMonitorRefTag);
            });
        });
    }


    @Scheduled(cron = "10 0 0 * * ?")// 每天午夜执行
    public void dailyStatisticsTask() {
        RMapCache<String, EnergyEquipmentMonitorRefTag> refRMapCache = energyEquipmentMonitorRefTagService.getMonitorMaps();
        refRMapCache.keySet().forEach(key -> {
            EXE.execute(() -> {
                EnergyEquipmentMonitorRefTag energyEquipmentMonitorRefTag = refRMapCache.get(key);
                doStatisticsTask(TimeGranularity.DAY, energyEquipmentMonitorRefTag);
            });
        });
    }


    @Scheduled(cron = "30 0 0 1 * ?")// 每月第一天执行
    public void monthlyStatisticsTask() {
        RMapCache<String, EnergyEquipmentMonitorRefTag> refRMapCache = energyEquipmentMonitorRefTagService.getMonitorMaps();
        refRMapCache.keySet().forEach(key -> {
            EXE.execute(() -> {
                EnergyEquipmentMonitorRefTag EnergyEquipmentMonitorRefTag = refRMapCache.get(key);
                doStatisticsTask(TimeGranularity.MONTH, EnergyEquipmentMonitorRefTag);
            });
        });
    }


    @Scheduled(cron = "45 0 0 1 1 ?")// 每年第一天执行
    public void yearlyStatisticsTask() {
        RMapCache<String, EnergyEquipmentMonitorRefTag> refRMapCache = energyEquipmentMonitorRefTagService.getMonitorMaps();
        refRMapCache.keySet().stream().forEach(key -> {
            EXE.execute(() -> {
                EnergyEquipmentMonitorRefTag EnergyEquipmentMonitorRefTag = refRMapCache.get(key);
                doStatisticsTask(TimeGranularity.YEAR, EnergyEquipmentMonitorRefTag);
            });
        });
    }


    @Scheduled(cron = "20 0/15 * * * ?")// 每15分钟执行
    public void minuteStatisticsTask() {
        RMapCache<String, EnergyEquipmentMonitorRefTag> refRMapCache = energyEquipmentMonitorRefTagService.getMonitorMaps();

        refRMapCache.keySet().forEach(key -> {
            EXE.execute(() -> {
                EnergyEquipmentMonitorRefTag EnergyEquipmentMonitorRefTag = refRMapCache.get(key);
                doStatisticsTask(TimeGranularity.MINUTE, EnergyEquipmentMonitorRefTag);
            });
        });
    }

    public void doStatisticsTask(TimeGranularity timeGranularity, EnergyEquipmentMonitorRefTag energyEquipmentMonitorRefTag) {
        Date date = new Date();
        long[] timeRange = TimeUtils.getPreviousTimeRange(timeGranularity);
        String query = "SELECT " +
                "mean(val) AS avg_value, " +
                "min(val) AS min_value, " +
                "max(val) AS max_value, " +
                "count(val) AS count, " +
                " LAST(val) AS last_value, " +
                " sum(val) AS total_value " +
                "FROM iot_device_reporting_data_pro " +
                "WHERE org_id = '" + energyEquipmentMonitorRefTag.getOrgId() + "'" +
                " and project_id = '" + energyEquipmentMonitorRefTag.getProjectId() + "'" +
                " and device_id = '" + energyEquipmentMonitorRefTag.getEquipmentId() + "'" +
                " and monitor_name = '" + energyEquipmentMonitorRefTag.getMonitorName() + "'" +
                " and  tag_name = '" + energyEquipmentMonitorRefTag.getTagName() + "'" +
                " and  timestamp >= " + timeRange[0] + " AND timestamp < " + timeRange[1] +
                " GROUP BY org_id, project_id,product_key, device_id, tag_name " +
                "ORDER BY time DESC";
        List<StatisticsTable> validStatisticsList = null;
        try {
            // 任务开始日志
            logger.info("开始执行{}统计任务，查询时间范围：{} - {}", timeGranularity.name(), timeRange[0], timeRange[1]);

            // 查询设备数据
            List<StatisticsTable> statisticsTableList = influxdbTemplate.selectList(query, StatisticsTable.class);

            // 如果未查询到数据
            if (statisticsTableList.isEmpty()) {
                logger.info("未找到过去{}的数据。query：{}", timeGranularity.name(), query);
                return;
            }

            // 处理统计数据
            validStatisticsList = processStatistics(statisticsTableList, date, timeGranularity, energyEquipmentMonitorRefTag);

            // 如果有有效数据，插入数据库
            if (!validStatisticsList.isEmpty()) {
                statisticsTableService.saveBatch(validStatisticsList);
                logger.info("成功插入 {} 条数据到数据库。", validStatisticsList.size());
            } else {
                logger.info("没有符合条件的数据需要插入。");
            }

            // 任务完成日志
            logger.info("{}统计任务执行完成。", timeGranularity.name());

        } catch (Exception e) {
            // 异常日志
            logger.error("{}统计任务执行失败。data:{}", timeGranularity.name(), e, validStatisticsList);
        }
    }

    /**
     * 处理统计数据的公共方法，返回符合条件的列表
     */
    private List<StatisticsTable> processStatistics(List<StatisticsTable> statisticsTableList, Date date, TimeGranularity timeGranularity, EnergyEquipmentMonitorRefTag energyEquipmentMonitorRefTag) {

        List<StatisticsTable> validStatisticsList = new ArrayList<>();

        for (StatisticsTable statisticsTable : statisticsTableList) {
            statisticsTable.setTimestamp(date);
            statisticsTable.setTimeGranularity(timeGranularity.getValue());

            DeviceBaseInfo deviceBaseInfo = deviceBaseInfoService.getById(statisticsTable.getDeviceId());
            if (deviceBaseInfo == null) {
                logger.warn("找不到 deviceId： {} 的 DeviceBaseInfo", statisticsTable.getDeviceId());
                continue; // 跳过此记录
            }
            if (StringUtils.isNotEmpty(energyEquipmentMonitorRefTag.getTagNameAliasName())) {
                statisticsTable.setTagNameAliasName(energyEquipmentMonitorRefTag.getTagNameAliasName());
            }
            // 设置设备类型和单位
            statisticsTable.setDeviceType(deviceBaseInfo.getClassName());
            statisticsTable.setUnit(energyEquipmentMonitorRefTag.getUnit());
            statisticsTable.setEnergyType(energyEquipmentMonitorRefTag.getEnergyType());
            statisticsTable.setId(UUID.randomUUID().toString());
            // 添加到有效列表
            validStatisticsList.add(statisticsTable);
            logger.info("Valid Statistics Data: {}", statisticsTable);
        }

        return validStatisticsList;
    }

}


